/*
MIT License

Copyright (c) 2022 МГТУ им. Н.Э. Баумана, кафедра ИУ-6, Михаил Фетисов,

https://bmstu.codes/lsx/simodo/loom
*/

#ifndef simodo_sbl_Machine
#define simodo_sbl_Machine

/*! \file OperationEngine.h
    \brief Класс управления состоянием машины SBL
*/

#include "simodo/interpret/StackOfNames_interface.h"
#include "ScriptOperationCode.h"


namespace simodo::interpret
{
    struct ExecuteRecordStructure_data
    {
        boundary_index_t    boundary_index    = UNDEFINED_BOUNDARY_INDEX;
        const ast::Node &   op;
        size_t              op_branches_index = 0;
    };

    class FunctionDefinition_data
    {
    public:
        enum class State
        {
            None = 0,
            Params = 1,
            Return_Type = 2,
            Body = 3,
        };

    private:
        const ast::Node *   _pop_return_type = nullptr;
        const ast::Node *   _pop_body        = nullptr;
        variable::Object    _closures;
        variable::Object    _params;
        variable::Variable  _return_type;
        State               _state = State::None;

    public:
        void reset() 
        {
            _closures.variables().clear();
            _pop_return_type = nullptr;
            _pop_body        = nullptr;
            _state = State::None;
            _params.variables().clear();
            _return_type = {};
        }

        const ast::Node *           pop_return_type()   const { return _pop_return_type; }
        const ast::Node *           pop_body()          const { return _pop_body; }
        const variable::Object &    closures()          const { return _closures; }
        const variable::Object &    params()            const { return _params; }
        const variable::Variable &  return_type()       const { return _return_type; }
        State                       state()             const { return _state; }

        void initiate(variable::Object & closures, const ast::Node * pop_return_type, const ast::Node * pop_body)
        {
            _closures.variables().swap(closures.variables());
            _pop_return_type = pop_return_type;
            _pop_body = pop_body;
            _state = State::Params;
            _params.variables().clear();
            _return_type = {};
        }
        void setParams(variable::Object & params)
        {
            _params.variables().swap(params.variables());
            _state = State::Return_Type;
        }
        void setReturnType(const variable::Variable & return_type)
        {
            _return_type = return_type;
            _state = State::Body;
        }

        variable::Variable createFunction() const
        {
            std::shared_ptr<variable::Object> function = std::make_shared<variable::Object>();

            function->variables().push_back({u"@", variable::InternalFunction {_pop_body, _closures}});
            function->variables().push_back(_return_type);

            for(const variable::Variable & v : _params.variables())
                function->variables().push_back(v);

            return {u"", {variable::ValueType::Function,function}};
        }
    };

    struct ExecuteCycle_data
    {
        boundary_index_t    boundary_index;
        const ast::Node *   pop_variable;
        const ast::Node *   pop_source;
        const ast::Node *   pop_expression;
        const ast::Node *   pop_body;

        name_index_t        variable_index = UNDEFINED_NAME_INDEX;
        variable::Variable  typed_variable = {};
        variable::Variable  source         = {};
        variable::index_t   source_counter = 0;
        variable::Variable  iterator       = {};

        ExecuteCycle_data() = delete;
        ExecuteCycle_data(boundary_index_t boundary_index, const ast::Node * pop_expression, const ast::Node * pop_body)
            : boundary_index(boundary_index)
            , pop_variable(nullptr)
            , pop_source(nullptr)
            , pop_expression(pop_expression)
            , pop_body(pop_body)
        {}
        ExecuteCycle_data(boundary_index_t boundary_index, const ast::Node * pop_variable, const ast::Node * pop_source, const ast::Node * pop_body)
            : boundary_index(boundary_index)
            , pop_variable(pop_variable)
            , pop_source(pop_source)
            , pop_expression(nullptr)
            , pop_body(pop_body)
        {}
    };

    enum class FiberFlowMode
    {
        None,
        InDemand,
        Prepared,
        Launched
    };
}

#endif // simodo_sbl_Machine
